package com.boruan.shengtangfeng.api.jwt.filter;

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.boruan.shengtangfeng.api.jwt.util.JwtUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import com.boruan.shengtangfeng.api.jwt.JwtUserFactory;
import com.boruan.shengtangfeng.api.jwt.UserSubject;
import com.boruan.shengtangfeng.api.jwt.exception.TokenException;
import com.boruan.shengtangfeng.core.entity.User;
import com.boruan.shengtangfeng.core.service.IUserService;
import com.boruan.shengtangfeng.core.utils.Consts;

/**
 * token的校验 该类继承自BasicAuthenticationFilter，在doFilterInternal方法中，
 * 从http头的Authorization 项读取token数据，然后用Jwts包提供的方法校验token的合法性。
 * 如果校验通过，就认为这是一个取得授权的合法请求
 */
public class JWTAuthenticationFilter extends BasicAuthenticationFilter {

	private static final Logger logger = LoggerFactory.getLogger(JWTAuthenticationFilter.class);

	@Autowired
	private JwtUtil jwtUtil;
	@Autowired
	private IUserService userService;
	@Autowired
    private RedisTemplate<String, Object> redisTemplate;
	private AuthenticationEntryPoint authenticationEntryPoint;
	private boolean ignoreFailure = false;

	public JWTAuthenticationFilter(AuthenticationManager authenticationManager) {
		super(authenticationManager);
	}

	public JWTAuthenticationFilter(AuthenticationManager authenticationManager,
			AuthenticationEntryPoint authenticationEntryPoint) {
		super(authenticationManager, authenticationEntryPoint);
		this.authenticationEntryPoint = authenticationEntryPoint;
	}

	@Override
	protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
			FilterChain filterChain) throws IOException, ServletException {
		httpServletResponse.setHeader("Access-Control-Allow-Origin", "*");
		httpServletResponse.setHeader("Access-Control-Allow-Methods", "POST,GET,PUT,OPTIONS,DELETE");
		httpServletResponse.setHeader("Access-Control-Max-Age", "3600");
		httpServletResponse.setHeader("Access-Control-Allow-Headers",
				"Authorization,Origin,X-Requested-With,Content-Type,Accept");
		httpServletResponse.setCharacterEncoding("UTF-8");
		httpServletResponse.setContentType("application/json; charset=utf-8");
		if (httpServletRequest.getMethod().equals("OPTIONS")) {
			httpServletResponse.setStatus(HttpServletResponse.SC_OK);
		}
		if (!httpServletRequest.getMethod().equals("OPTIONS")) {
			try {
				final String authToken = jwtUtil.getToken(httpServletRequest);
				if (logger.isInfoEnabled()) {
					if (StringUtils.isNotBlank(authToken)) {
						logger.info(authToken);
					}
				}
				if (StringUtils.isNoneBlank(authToken)) {
					Long userId = jwtUtil.getUserIdFromToken(authToken);
					if (logger.isInfoEnabled()) {
						logger.info(
								"JwtAuthenticationTokenFilter_doFilterInternal checking authentication " + userId);
					}
					if (userId != null && SecurityContextHolder.getContext().getAuthentication() == null) {// token校验通过
						// 根据account去数据库中查询user数据，足够信任token的情况下，可以省略这一步
					       
						if (jwtUtil.validateToken(authToken)) {
							// 需要判断用户是否验证通过，如果没有通过，认证方法忽略
						    
//							UserSubject userDetails = jwtUtil.getJwtUserFromToken(authToken);
							User user=userService.findById(userId);
							if (user.getIsLocked()==true){
								throw new TokenException("已被封号");
							}
							UserSubject userDetails = JwtUserFactory.create(user);
							String oldToken=(String)redisTemplate.opsForValue().get(Consts.USER_TOKEN_KEY + userDetails.getId());
							//TODO 互踢先去掉
//							if(!StringUtils.equals(authToken, oldToken)) {
//							    throw new TokenException("互踢校验异常");
//							}
							UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
									userDetails, null, userDetails.getAuthorities());
							authentication
									.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpServletRequest));
							if (logger.isInfoEnabled()) {
								logger.info("JwtAuthenticationTokenFilter_doFilterInternal  用户验证token,验证用户： "
										+ userId + ", setting security context");
							}
							SecurityContextHolder.getContext().setAuthentication(authentication);
						} else {
							throw new TokenException("token校验失败");
						}
					} else {
						throw new TokenException("token解析错误");
					}
				}
			} catch (AuthenticationException failed) {
				SecurityContextHolder.clearContext();

				if (logger.isDebugEnabled()) {
					logger.debug("Authentication request for failed: " + failed);
				}

				if (this.ignoreFailure) {
					filterChain.doFilter(httpServletRequest, httpServletResponse);
				} else {
					authenticationEntryPoint.commence(httpServletRequest, httpServletResponse, failed);
				}
				return;
			}
		}
		filterChain.doFilter(httpServletRequest, httpServletResponse);

	}
}
